#pragma once

#include <pthread.h>

template <class T>
class BlockQueue
{
public:
    BlockQueue(int cap) : _capacity(cap)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_producers, nullptr);
        pthread_cond_init(&_consumers, nullptr);
        _consumers_water_level = (cap / 3) * 2;
        _producers_water_level = cap / 3;
        // std::cout << _consumers_water_level << " : " << _producers_water_level << std::endl;
    }

    bool IsFull()
    {
        return _q.size() == _capacity;
    }

    bool IsEmpty()
    {
        return _q.size() == 0;
    }
    size_t Size()
    {
        return _q.size();
    }
    void Push(T &in)
    {

        LockGuard lockguard(&_lock); 
        // pthread_mutex_lock(&_lock);
        //细节 如果只有一个空间，但是用 pthread_cond_broadcast()唤醒一批进程，一唤醒来都是执行if以后的代码就会出现问题（IsFull() 不满足条件 ） 
        // if (IsFull()) // queue满了,就去等待
        while(IsFull()) //用循环来增加代码的健壮性       
        {
            pthread_cond_wait(&_producers, &_lock);
        }
        _q.push(in);
        // if (_capacity > _consumers_water_level)
        // {
        //     pthread_cond_signal(&_consumers); // 生产一个就通知消费者消费
        // }
        pthread_cond_signal(&_consumers); // 生产一个就通知消费者消费
        // pthread_mutex_unlock(&_lock);
    }

    void Pop(T *out)
    {
        LockGuard lockguard(&_lock); 
        // pthread_mutex_lock(&_lock);
        // if (IsEmpty()) // queue为空就去等待
        while(IsEmpty())
        {
            pthread_cond_wait(&_consumers, &_lock);
        }

        *out = _q.front();
        _q.pop();
        // if (_capacity < _producers_water_level)
        // {
        // pthread_cond_signal(&_producers); // 消费了一个数据就通知生产者生产了
        // }
        pthread_cond_signal(&_producers); // 消费了一个数据就通知生产者生产了
        // pthread_mutex_unlock(&_lock);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_consumers);
        pthread_cond_destroy(&_producers);
    }
private:
    std::queue<T> _q;
    int _capacity;
    pthread_mutex_t _lock;
    pthread_cond_t _producers;
    pthread_cond_t _consumers;
    // 设计通知模式
    int _consumers_water_level;
    int _producers_water_level;
};